home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume22 / undel2 / part03 < prev    next >
Encoding:
Internet Message Format  |  1990-06-07  |  54.2 KB

  1. Subject:  v22i027:  MIT Athena delete/undelete programs, release 2, Part03/03
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 1670c4cf e787c704 dbea1032 2fa69b6a
  5.  
  6. Submitted-by: "Jonathan I. Kamens" <jik@pit-manager.mit.edu>
  7. Posting-number: Volume 22, Issue 27
  8. Archive-name: undel2/part03
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 3 (of 3)."
  17. # Contents:  delete.c directories.c pattern.c
  18. # Wrapped by rsalz@papaya.bbn.com on Mon May  7 16:54:02 1990
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'delete.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'delete.c'\"
  22. else
  23. echo shar: Extracting \"'delete.c'\" \(13132 characters\)
  24. sed "s/^X//" >'delete.c' <<'END_OF_FILE'
  25. X/*
  26. X * $Source: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/delete.c,v $
  27. X * $Author: jik $
  28. X *
  29. X * This program is a replacement for rm.  Instead of actually deleting
  30. X * files, it marks them for deletion by prefixing them with a ".#"
  31. X * prefix.
  32. X *
  33. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  34. X * For copying and distribution information, see the file "mit-copyright.h."
  35. X */
  36. X
  37. X#if (!defined(lint) && !defined(SABER))
  38. X     static char rcsid_delete_c[] = "$Header: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/delete.c,v 1.21 89/12/15 04:39:22 jik Exp $";
  39. X#endif
  40. X
  41. X#include <sys/types.h>
  42. X#include <stdio.h>
  43. X#include <sys/stat.h>
  44. X#include <sys/dir.h>
  45. X#include <strings.h>
  46. X#include <sys/param.h>
  47. X#include <sys/file.h>
  48. X#include <errno.h>
  49. X#include "errors.h"
  50. X#include "delete_errs.h"
  51. X#include "util.h"
  52. X#include "delete.h"
  53. X#include "mit-copyright.h"
  54. X
  55. X
  56. X
  57. X/*
  58. X * ALGORITHM:
  59. X *
  60. X * 1. Parse command-line arguments and set flags.
  61. X * 2. Call the function delete() for each filename command-line argument.
  62. X *
  63. X * delete():
  64. X *
  65. X * 1. Can the file be lstat'd?
  66. X *    no -- abort
  67. X *    yes -- continue
  68. X * 2. Is the file a directory?
  69. X *    yes -- is it a dotfile?
  70. X *           yes -- abort
  71. X *           no -- continue
  72. X *        -- is the filesonly option set?
  73. X *           yes -- is the recursive option specified?
  74. X *                  yes -- continue
  75. X *                  no -- abort
  76. X *           no -- is the directory empty?
  77. X *                  yes -- remove it
  78. X *                  no -- is the directoriesonly option set?
  79. X *               yes -- abort
  80. X *               no -- continue
  81. X *                -- is the recursive option specified?
  82. X *               yes -- continue
  83. X *               no -- abort
  84. X *    no -- is the directoriesonly option set?
  85. X *         yes -- abort
  86. X *         no -- continue
  87. X * 3. If the file is a file, remove it.
  88. X * 4. If the file is a directory, open it and pass each of its members
  89. X *    (excluding . files) to delete().
  90. X */
  91. X
  92. X
  93. Xint force, interactive, recursive, noop, verbose, filesonly, directoriesonly;
  94. Xint emulate_rm;
  95. Xextern int errno;
  96. X
  97. Xmain(argc, argv)
  98. Xint argc;
  99. Xchar *argv[];
  100. X{
  101. X     extern char *optarg;
  102. X     extern int optind;
  103. X     int arg;
  104. X     
  105. X     whoami = lastpart(argv[0]);
  106. X
  107. X     initialize_del_error_table();
  108. X     
  109. X     force = interactive = recursive = noop = verbose = filesonly =
  110. X      directoriesonly = emulate_rm = 0;
  111. X     while ((arg = getopt(argc, argv, "efirnvFD")) != -1) {
  112. X      switch (arg) {
  113. X      case 'r':
  114. X           recursive++;
  115. X           if (directoriesonly) {
  116. X                    fprintf(stderr, "%s: -r and -D are mutually exclusive.\n",
  117. X                            whoami);
  118. X                    usage();
  119. X            exit(1);
  120. X           }
  121. X           break;
  122. X      case 'f':
  123. X           force++;
  124. X           break;
  125. X      case 'i':
  126. X           interactive++;
  127. X           break;
  128. X      case 'n':
  129. X           noop++;
  130. X           break;
  131. X      case 'v':
  132. X           verbose++;
  133. X           break;
  134. X      case 'e':
  135. X           emulate_rm++;
  136. X           break;
  137. X      case 'F':
  138. X           filesonly++;
  139. X           if (directoriesonly) {
  140. X            fprintf(stderr, "%s: -F and -D are mutually exclusive.\n",
  141. X                            whoami);
  142. X                    usage();
  143. X            exit(1);
  144. X           }
  145. X           break;
  146. X      case 'D':
  147. X           directoriesonly++;
  148. X           if (recursive) {
  149. X                    fprintf(stderr, "%s: -r and -D are mutually exclusive.\n",
  150. X                            whoami);
  151. X                    usage();
  152. X            exit(1);
  153. X           }
  154. X           if (filesonly) {
  155. X                    fprintf(stderr, "%s: -F and -D are mutually exclusive.\n",
  156. X                            whoami);
  157. X                    usage();
  158. X            exit(1);
  159. X           }
  160. X           break;
  161. X      default:
  162. X           usage();
  163. X           exit(1);
  164. X      }
  165. X     }
  166. X     report_errors = ! (force || emulate_rm);
  167. X     
  168. X     if (optind == argc) {
  169. X      if (! force) {
  170. X           fprintf(stderr, "%s: no files specified.\n", whoami);
  171. X           usage();
  172. X      }
  173. X      exit(force ? 0 : 1);
  174. X     }
  175. X     while (optind < argc) {
  176. X      if (delete(argv[optind], 0))
  177. X           error(argv[optind]);
  178. X      optind++;
  179. X     }
  180. X     exit(((! force) && error_occurred) ? 1 : 0);
  181. X}
  182. X
  183. X
  184. X
  185. Xusage()
  186. X{
  187. X     printf("Usage: %s [ options ] filename ...\n", whoami);
  188. X     printf("Options are:\n");
  189. X     printf("     -r     recursive\n");
  190. X     printf("     -i     interactive\n");
  191. X     printf("     -f     force\n");
  192. X     printf("     -n     noop\n");
  193. X     printf("     -v     verbose\n");
  194. X     printf("     -F     files only\n");
  195. X     printf("     -D     directories only\n");
  196. X     printf("     --     end options and start filenames\n");
  197. X     printf("-r and -D are mutually exclusive\n");
  198. X     printf("-F and -D are mutually exclusive\n");
  199. X}
  200. X
  201. X
  202. X
  203. X
  204. Xdelete(filename, recursed)
  205. Xchar *filename;
  206. Xint recursed;
  207. X{
  208. X     struct stat stat_buf;
  209. X     int retval;
  210. X     
  211. X     /* can the file be lstat'd? */
  212. X     if (lstat(filename, &stat_buf) == -1) {
  213. X      set_error(errno);
  214. X      if (emulate_rm && (! force))
  215. X           fprintf(stderr, "%s: %s nonexistent\n", whoami, filename);
  216. X      error(filename);
  217. X      return error_code;
  218. X     }
  219. X
  220. X     /* is the file a directory? */
  221. X     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
  222. X      /* is the file a dot file? */
  223. X      if (is_dotfile(lastpart(filename))) {
  224. X           set_error(DELETE_IS_DOTFILE);
  225. X           if (emulate_rm && (! force))
  226. X            fprintf(stderr, "%s: cannot remove `.' or `..'\n", whoami);
  227. X           error(filename);
  228. X           return error_code;
  229. X      }
  230. X
  231. X      /* is the filesonly option set? */
  232. X      if (filesonly) {
  233. X           /* is the recursive option specified? */
  234. X           if (recursive) {
  235. X            if (retval = recursive_delete(filename, stat_buf,
  236. X                          recursed)) {
  237. X             error(filename);
  238. X             return retval;
  239. X            }
  240. X           }
  241. X           else {
  242. X            if (emulate_rm && (! force))
  243. X             fprintf(stderr, "%s: %s directory\n", whoami,
  244. X                 filename);
  245. X            set_error(DELETE_CANT_DEL_DIR);
  246. X            error(filename);
  247. X            return error_code;
  248. X           }
  249. X      }
  250. X      else {
  251. X           /* is the directory empty? */
  252. X           if ((retval = empty_directory(filename)) < 0) {
  253. X            error(filename);
  254. X            if (! emulate_rm)
  255. X             return error_code;
  256. X           }
  257. X
  258. X           if (retval > 0) {
  259. X            /* remove it */
  260. X            if (retval = do_move(filename, stat_buf, 0)) {
  261. X             error(filename);
  262. X             return error_code;
  263. X            }
  264. X           }
  265. X           else {
  266. X            /* is the directoriesonly option set? */
  267. X            if (directoriesonly) {
  268. X             if (emulate_rm && (! force))
  269. X                  fprintf(stderr, "%s: %s: Directory not empty\n",
  270. X                      whoami, filename);
  271. X             set_error(DELETE_DIR_NOT_EMPTY);
  272. X             error(filename);
  273. X             return error_code;
  274. X            }
  275. X            else {
  276. X             /* is the recursive option specified? */
  277. X             if (recursive) {
  278. X                  if (retval = recursive_delete(filename, stat_buf,
  279. X                                recursed)) {
  280. X                   error(filename);
  281. X                   return error_code;
  282. X                  }
  283. X             }
  284. X             else {
  285. X                  if (emulate_rm && (! force))
  286. X                   fprintf(stderr, "%s: %s not empty\n",
  287. X                       whoami, filename);
  288. X                  set_error(DELETE_DIR_NOT_EMPTY);
  289. X                  error(filename);
  290. X                  return error_code;
  291. X             }
  292. X            }
  293. X           }
  294. X      }
  295. X     }
  296. X     else {
  297. X      /* is the directoriesonly option set? */
  298. X      if (directoriesonly) {
  299. X           if (emulate_rm && (! force))
  300. X            fprintf(stderr, "%s: %s: Not a directory\n", whoami,
  301. X                filename);
  302. X           set_error(DELETE_CANT_DEL_FILE);
  303. X           error(filename);
  304. X           return error_code;
  305. X      }
  306. X      else {
  307. X           if (retval = do_move(filename, stat_buf, 0)) {
  308. X            error(filename);
  309. X            return error_code;
  310. X           }
  311. X      }
  312. X     }
  313. X     return 0;
  314. X}
  315. X      
  316. X
  317. X         
  318. X             
  319. X           
  320. Xempty_directory(filename)
  321. Xchar *filename;
  322. X{
  323. X     DIR *dirp;
  324. X     struct direct *dp;
  325. X
  326. X     dirp = Opendir(filename);
  327. X     if (! dirp) {
  328. X      set_error(errno);
  329. X      error(filename);
  330. X      return -1;
  331. X     }
  332. X     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  333. X      if (is_dotfile(dp->d_name))
  334. X           continue;
  335. X      if (is_deleted(dp->d_name))
  336. X           continue;
  337. X      else {
  338. X           closedir(dirp);
  339. X           return 0;
  340. X      }
  341. X     }
  342. X     closedir(dirp);
  343. X     return 1;
  344. X}
  345. X
  346. X
  347. X
  348. X
  349. Xrecursive_delete(filename, stat_buf, recursed)
  350. Xchar *filename;
  351. Xstruct stat stat_buf;
  352. Xint recursed;
  353. X{
  354. X     DIR *dirp;
  355. X     struct direct *dp;
  356. X     int status = 0;
  357. X     char newfile[MAXPATHLEN];
  358. X     int retval = 0;
  359. X     
  360. X     if (interactive && recursed) {
  361. X      printf("%s: remove directory %s? ", whoami, filename);
  362. X      if (! yes()) {
  363. X           set_status(DELETE_NOT_DELETED);
  364. X           return error_code;
  365. X      }
  366. X     }
  367. X     dirp = Opendir(filename);
  368. X     if (! dirp) {
  369. X      if (emulate_rm && (! force))
  370. X           fprintf(stderr, "%s: %s not changed\n", whoami, filename);
  371. X      set_error(errno);
  372. X      error(filename);
  373. X      return error_code;
  374. X     }
  375. X     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  376. X      if (is_dotfile(dp->d_name))
  377. X           continue;
  378. X      if (is_deleted(dp->d_name))
  379. X           continue;
  380. X      else {
  381. X           (void) strcpy(newfile, append(filename, dp->d_name));
  382. X           if (! *newfile) {
  383. X            error(filename);
  384. X            status = error_code;
  385. X           }
  386. X
  387. X           retval = delete(newfile, 1);
  388. X           if (retval) {
  389. X            error(newfile);
  390. X            status = retval;
  391. X           }
  392. X      }
  393. X     }
  394. X     closedir(dirp);
  395. X
  396. X     if (status && (! emulate_rm)) {
  397. X      set_warning(DELETE_DIR_NOT_EMPTY);
  398. X      error(filename);
  399. X     }
  400. X     else
  401. X      retval = do_move(filename, stat_buf, status);
  402. X     
  403. X     if (retval)
  404. X      status = retval;
  405. X
  406. X     return status;
  407. X}
  408. X
  409. X                     
  410. X
  411. X
  412. X
  413. X
  414. Xdo_move(filename, stat_buf, subs_not_deleted)
  415. Xchar *filename;
  416. Xstruct stat stat_buf;
  417. Xint subs_not_deleted; /* If the file in question is a directory, and  */
  418. X              /* there is something underneath it that hasn't */
  419. X              /* been removed, this will be set to true.      */
  420. X                      /* The program asks if the user wants to delete */
  421. X              /* the directory, and if the user says yes,     */
  422. X              /* checks the value of subs_not_deleted.  If    */
  423. X              /* it's true, an error results.                 */
  424. X                      /* This is used only when emulating rm.         */
  425. X{
  426. X     char *last;
  427. X     char buf[MAXPATHLEN];
  428. X     char name[MAXNAMLEN];
  429. X     struct stat deleted_buf;
  430. X
  431. X     (void) strncpy(buf, filename, MAXPATHLEN);
  432. X     last = lastpart(buf);
  433. X     if (strlen(last) > MAXNAMLEN) {
  434. X      if (emulate_rm && (! force))
  435. X           fprintf(stderr, "%s: %s: filename too long\n", whoami,
  436. X               filename);
  437. X      set_error(ENAMETOOLONG);
  438. X      error(filename);
  439. X      return error_code;
  440. X     }
  441. X     (void) strcpy(name, last);
  442. X     if (strlen(buf) + 3 > MAXPATHLEN) {
  443. X      if (emulate_rm && (! force))
  444. X           fprintf(stderr, "%s: %s: pathname too long\n", whoami,
  445. X               filename);
  446. X      set_error(ENAMETOOLONG);
  447. X      error(filename);
  448. X      return error_code;
  449. X     }
  450. X     *last = '\0';
  451. X     (void) strcat(buf, ".#");
  452. X     (void) strcat(buf, name);
  453. X     if (interactive) {
  454. X      printf("%s: remove %s? ", whoami, filename);
  455. X      if (! yes()) {
  456. X           set_status(DELETE_NOT_DELETED);
  457. X           return error_code;
  458. X      }
  459. X     }
  460. X     else if ((! force) && ((stat_buf.st_mode & S_IFMT) != S_IFLNK)
  461. X          && access(filename, W_OK)) {
  462. X      if (emulate_rm)
  463. X           printf("%s: override protection %o for %s? ", whoami,
  464. X              stat_buf.st_mode & 0777, filename);
  465. X      else
  466. X           printf("%s: File %s not writeable.  Delete anyway? ", whoami,
  467. X              filename);
  468. X      if (! yes()) {
  469. X           set_status(DELETE_NOT_DELETED);
  470. X           return error_code;
  471. X      }
  472. X     }
  473. X     if (emulate_rm && subs_not_deleted) {
  474. X      if (! force)
  475. X           fprintf(stderr, "%s: %s not removed\n", whoami, filename);
  476. X      return 1;
  477. X     }
  478. X     if (noop) {
  479. X      fprintf(stderr, "%s: %s would be removed\n", whoami, filename);
  480. X      return 0;
  481. X     }
  482. X     if ((! lstat(buf, &deleted_buf)) && unlink_completely(buf)) {
  483. X      if (emulate_rm && (! force))
  484. X           fprintf(stderr, "%s: %s not removed\n", whoami, filename);
  485. X      error(filename);
  486. X      return error_code;
  487. X     }
  488. X     if (rename(filename, buf)) {
  489. X      if (emulate_rm && (! force))
  490. X           fprintf(stderr, "%s: %s not removed\n", whoami, filename);
  491. X      set_error(errno);
  492. X      error(filename);
  493. X      return error_code;
  494. X     }
  495. X     else {
  496. X      if (verbose)
  497. X           fprintf(stderr, "%s: %s removed\n", whoami, filename);
  498. X      return 0;
  499. X     }
  500. X}
  501. X
  502. X
  503. X
  504. Xunlink_completely(filename)
  505. Xchar *filename;
  506. X{
  507. X     char buf[MAXPATHLEN];
  508. X     struct stat stat_buf;
  509. X     DIR *dirp;
  510. X     struct direct *dp;
  511. X     int status = 0;
  512. X     int retval;
  513. X     
  514. X     if (lstat(filename, &stat_buf)) {
  515. X      set_error(errno);
  516. X      error(filename);
  517. X      return error_code;
  518. X     }
  519. X
  520. X     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
  521. X      dirp = Opendir(filename);
  522. X      if (! dirp) {
  523. X           set_error(errno);
  524. X           error(filename);
  525. X           return error_code;
  526. X      }
  527. X      
  528. X      for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  529. X           if (is_dotfile(dp->d_name))
  530. X            continue;
  531. X           (void) strcpy(buf, append(filename, dp->d_name));
  532. X           if (! *buf) {
  533. X            status = error_code;
  534. X            error(filename);
  535. X            continue;
  536. X           }
  537. X           retval = unlink_completely(buf);
  538. X           if (retval) {
  539. X            status = retval;
  540. X            error(filename);
  541. X           }
  542. X      }
  543. X      closedir(dirp);
  544. X
  545. X      if (status)
  546. X           return status;
  547. X
  548. X      retval = rmdir(filename);
  549. X      if (retval) {
  550. X           set_error(errno);
  551. X           error(filename);
  552. X           return errno;
  553. X      }
  554. X     }
  555. X     else {
  556. X      retval = unlink(filename);
  557. X      if (retval) {
  558. X           set_error(errno);
  559. X           error(filename);
  560. X           return error_code;
  561. X      }
  562. X      else
  563. X           return 0;
  564. X     }
  565. X     return 0;
  566. X}
  567. END_OF_FILE
  568. if test 13132 -ne `wc -c <'delete.c'`; then
  569.     echo shar: \"'delete.c'\" unpacked with wrong size!
  570. fi
  571. # end of 'delete.c'
  572. fi
  573. if test -f 'directories.c' -a "${1}" != "-c" ; then 
  574.   echo shar: Will not clobber existing file \"'directories.c'\"
  575. else
  576. echo shar: Extracting \"'directories.c'\" \(14682 characters\)
  577. sed "s/^X//" >'directories.c' <<'END_OF_FILE'
  578. X/*
  579. X * $Source: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/directories.c,v $
  580. X * $Author: jik $
  581. X * 
  582. X * This program is part of a package including delete, undelete,
  583. X * lsdel, expunge and purge.  The software suite is meant as a
  584. X * replacement for rm which allows for file recovery.
  585. X * 
  586. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  587. X * For copying and distribution information, see the file "mit-copyright.h."
  588. X */
  589. X
  590. X#if !defined(lint) && !defined(SABER)
  591. X     static char rcsid_directories_c[] = "$Header: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/directories.c,v 1.15 89/11/22 21:32:24 jik Exp $";
  592. X#endif
  593. X
  594. X#include <stdio.h>
  595. X#include <sys/types.h>
  596. X#include <sys/stat.h>
  597. X#include <sys/param.h>
  598. X#include <sys/dir.h>
  599. X#include <strings.h>
  600. X#include <errno.h>
  601. X#include <com_err.h>
  602. X#include "delete_errs.h"
  603. X#include "directories.h"
  604. X#include "util.h"
  605. X#include "mit-copyright.h"
  606. X#include "errors.h"
  607. X
  608. Xextern char *realloc();
  609. Xextern long time();
  610. Xextern int errno;
  611. X
  612. Xstatic filerec root_tree;
  613. Xstatic filerec cwd_tree;
  614. X
  615. Xvoid free_leaf();
  616. X
  617. X /* These are not static because external routines need to be able to */
  618. X /* access them.                               */
  619. Xtime_t current_time;
  620. X
  621. X
  622. Xstatic filerec default_cwd = {
  623. X     "",
  624. X     (filerec *) NULL,
  625. X     (filerec *) NULL,
  626. X     (filerec *) NULL,
  627. X     (filerec *) NULL,
  628. X     (filerec *) NULL,
  629. X     False,
  630. X     False,
  631. X     {0}
  632. X};
  633. X
  634. Xstatic filerec default_root = {
  635. X     "/",
  636. X     (filerec *) NULL,
  637. X     (filerec *) NULL,
  638. X     (filerec *) NULL,
  639. X     (filerec *) NULL,
  640. X     (filerec *) NULL,
  641. X     False,
  642. X     False,
  643. X     {0}
  644. X};
  645. X
  646. Xstatic filerec default_directory = {
  647. X     "",
  648. X     (filerec *) NULL,
  649. X     (filerec *) NULL,
  650. X     (filerec *) NULL,
  651. X     (filerec *) NULL,
  652. X     (filerec *) NULL,
  653. X     False,
  654. X     False,
  655. X     {0}
  656. X};
  657. X
  658. Xstatic filerec default_file = {
  659. X     "",
  660. X     (filerec *) NULL,
  661. X     (filerec *) NULL,
  662. X     (filerec *) NULL,
  663. X     (filerec *) NULL,
  664. X     (filerec *) NULL,
  665. X     False,
  666. X     False,
  667. X     {0}
  668. X};
  669. X
  670. X
  671. Xfilerec *get_root_tree()
  672. X{
  673. X     return(&root_tree);
  674. X}
  675. X
  676. X
  677. X
  678. Xfilerec *get_cwd_tree()
  679. X{
  680. X     return(&cwd_tree);
  681. X}
  682. X
  683. X
  684. Xint initialize_tree()
  685. X{
  686. X     int retval;
  687. X     
  688. X     root_tree = default_root;
  689. X     cwd_tree = default_cwd;
  690. X
  691. X     current_time = time((time_t *)0);
  692. X     if (retval = get_specs(".", &cwd_tree.specs, FOLLOW_LINKS)) {
  693. X      error("get_specs on .");
  694. X      return retval;
  695. X     }
  696. X     if (retval = get_specs("/", &root_tree.specs, FOLLOW_LINKS)) {
  697. X      error("get_specs on /");
  698. X      return retval;
  699. X     }
  700. X     return 0;
  701. X}
  702. X
  703. X
  704. Xint add_path_to_tree(path, leaf)
  705. Xchar *path;
  706. Xfilerec **leaf;
  707. X{
  708. X     filerec *parent;
  709. X     char next_name[MAXNAMLEN];
  710. X     char lpath[MAXPATHLEN], built_path[MAXPATHLEN], *ptr;
  711. X     struct stat specs;
  712. X     int retval;
  713. X     
  714. X     if (retval = get_specs(path, &specs, DONT_FOLLOW_LINKS)) {
  715. X      char error_buf[MAXPATHLEN+14];
  716. X
  717. X      (void) sprintf(error_buf, "get_specs on %s", path);
  718. X      error(error_buf);
  719. X      return retval;
  720. X     }
  721. X     
  722. X     (void) strcpy(lpath, path); /* we don't want to damage the user's */
  723. X                 /* string */
  724. X     ptr = lpath;
  725. X     if (*ptr == '/') {
  726. X      parent = &root_tree;
  727. X      ptr++;
  728. X      (void) strcpy(built_path, "/");
  729. X     }
  730. X     else if (! strncmp(ptr, "./", 2)) {
  731. X      parent = &cwd_tree;
  732. X      ptr += 2;
  733. X      *built_path = '\0';
  734. X     }
  735. X     else {
  736. X      parent = &cwd_tree;
  737. X      *built_path = '\0';
  738. X     }
  739. X     
  740. X     (void) strcpy(next_name, firstpart(ptr, ptr));
  741. X     while (*ptr) {
  742. X      (void) strcat(built_path, next_name);
  743. X      if (retval = add_directory_to_parent(parent, next_name, False,
  744. X                           &parent)) {
  745. X           error("add_directory_to_parent");
  746. X           return retval;
  747. X      }
  748. X      (void) strcpy(next_name, firstpart(ptr, ptr));
  749. X      if (retval = get_specs(built_path, &parent->specs, FOLLOW_LINKS)) {
  750. X           char error_buf[MAXPATHLEN+14];
  751. X
  752. X           (void) sprintf(error_buf, "get_specs on %s", built_path);
  753. X           error(error_buf);
  754. X           return retval;
  755. X      }
  756. X      (void) strcat(built_path, "/");
  757. X     }
  758. X     if ((specs.st_mode & S_IFMT) == S_IFDIR) {
  759. X      retval = add_directory_to_parent(parent, next_name, True, leaf);
  760. X      if (retval) {
  761. X           error("add_directory_to_parent");
  762. X           return retval;
  763. X      }
  764. X     }
  765. X     else {
  766. X      retval = add_file_to_parent(parent, next_name, True, leaf);
  767. X      if (retval) {
  768. X           error("add_file_to_parent");
  769. X           return retval;
  770. X      }
  771. X     }          
  772. X
  773. X     (*leaf)->specs = specs;
  774. X
  775. X     return 0;
  776. X}
  777. X
  778. X
  779. X
  780. X
  781. Xint get_specs(path, specs, follow)
  782. Xchar *path;
  783. Xstruct stat *specs;
  784. Xint follow; /* follow symlinks or not? */
  785. X{
  786. X     int status;
  787. X     
  788. X     if (strlen(path)) if ((path[strlen(path) - 1] == '/') &&
  789. X               (strlen(path) != 1))
  790. X      path[strlen(path) - 1] = '\0';
  791. X     if (follow == FOLLOW_LINKS)
  792. X      status = stat(path, specs);
  793. X     else 
  794. X      status = lstat(path, specs);
  795. X
  796. X     if (status) {
  797. X      set_error(errno);
  798. X      error(path);
  799. X      return error_code;
  800. X     }
  801. X
  802. X     return 0;
  803. X}
  804. X
  805. X
  806. X
  807. Xfilerec *next_leaf(leaf)
  808. Xfilerec *leaf;
  809. X{
  810. X     filerec *new;
  811. X
  812. X     if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
  813. X      new = first_in_directory(leaf);
  814. X      if (new)
  815. X           return(new);
  816. X      new = next_directory(leaf);
  817. X      return(new);
  818. X     }
  819. X     else {
  820. X      new = next_in_directory(leaf);
  821. X      return(new);
  822. X     }
  823. X}
  824. X
  825. X
  826. Xfilerec *next_specified_leaf(leaf)
  827. Xfilerec *leaf;
  828. X{
  829. X     while (leaf = next_leaf(leaf))
  830. X     if (leaf->specified)
  831. X      return(leaf);
  832. X     return((filerec *) NULL);
  833. X}
  834. X
  835. X
  836. Xfilerec *next_directory(leaf)
  837. Xfilerec *leaf;
  838. X{
  839. X     filerec *ret;
  840. X     if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
  841. X      leaf = leaf->parent;
  842. X     if (leaf)
  843. X      ret = leaf->next;
  844. X     else
  845. X      ret = (filerec *) NULL;
  846. X     if (ret) if (ret->freed)
  847. X      ret = next_directory(ret);
  848. X     return(ret);
  849. X}
  850. X
  851. X
  852. Xfilerec *next_specified_directory(leaf)
  853. Xfilerec *leaf;
  854. X{
  855. X     while (leaf = next_directory(leaf))
  856. X      if (leaf->specified)
  857. X           return(leaf);
  858. X     return ((filerec *) NULL);
  859. X}
  860. X
  861. X
  862. X
  863. Xfilerec *next_in_directory(leaf)
  864. Xfilerec *leaf;
  865. X{
  866. X     filerec *ret;
  867. X
  868. X     if (leaf->next)
  869. X      ret = leaf->next;
  870. X     else if (((leaf->specs.st_mode & S_IFMT) != S_IFDIR) && leaf->parent)
  871. X      ret = leaf->parent->dirs;
  872. X     else
  873. X      ret = (filerec *) NULL;
  874. X     if (ret) if (ret->freed)
  875. X      ret = next_in_directory(ret);
  876. X     return (ret);
  877. X}
  878. X
  879. X
  880. X
  881. X
  882. Xfilerec *next_specified_in_directory(leaf)
  883. Xfilerec *leaf;
  884. X{
  885. X     while (leaf = next_in_directory(leaf))
  886. X      if (leaf->specified)
  887. X           return(leaf);
  888. X     return ((filerec *) NULL);
  889. X}
  890. X
  891. X
  892. X
  893. Xfilerec *first_in_directory(leaf)
  894. Xfilerec *leaf;
  895. X{
  896. X     filerec *ret;
  897. X
  898. X     if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
  899. X      ret = (filerec *) NULL;
  900. X     else if (leaf->files)
  901. X      ret = leaf->files;
  902. X     else if (leaf->dirs)
  903. X      ret =  leaf->dirs;
  904. X     else
  905. X      ret = (filerec *) NULL;
  906. X     if (ret) if (ret->freed)
  907. X      ret = next_in_directory(ret);
  908. X     return(ret);
  909. X}
  910. X
  911. X
  912. Xfilerec *first_specified_in_directory(leaf)
  913. Xfilerec *leaf;
  914. X{
  915. X     leaf = first_in_directory(leaf);
  916. X     if (! leaf)
  917. X      return((filerec *) NULL);
  918. X     
  919. X     if (leaf->specified)
  920. X      return(leaf);
  921. X     else
  922. X      leaf = next_specified_in_directory(leaf);
  923. X     return (leaf);
  924. X}
  925. X
  926. X
  927. Xvoid print_paths_from(leaf)
  928. Xfilerec *leaf;
  929. X{
  930. X     char buf[MAXPATHLEN];
  931. X
  932. X     printf("%s\n", get_leaf_path(leaf, buf));
  933. X     if (leaf->dirs)
  934. X      print_paths_from(leaf->dirs);
  935. X     if (leaf->files)
  936. X      print_paths_from(leaf->files);
  937. X     if (leaf->next)
  938. X      print_paths_from(leaf->next);
  939. X}
  940. X
  941. X
  942. Xvoid print_specified_paths_from(leaf)
  943. Xfilerec *leaf;
  944. X{
  945. X     char buf[MAXPATHLEN];
  946. X
  947. X     if (leaf->specified)
  948. X      printf("%s\n", get_leaf_path(leaf, buf));
  949. X     if (leaf->dirs)
  950. X      print_specified_paths_from(leaf->dirs);
  951. X     if (leaf->files)
  952. X      print_specified_paths_from(leaf->files);
  953. X     if (leaf->next)
  954. X      print_specified_paths_from(leaf->next);
  955. X}
  956. X     
  957. X
  958. Xint add_file_to_parent(parent, name, specified, last)
  959. Xfilerec *parent, **last;
  960. Xchar *name;
  961. XBoolean specified;
  962. X{
  963. X     filerec *files;
  964. X
  965. X     *last = files = (filerec *) NULL;
  966. X     files = parent->files;
  967. X     while (files) {
  968. X      if (! strcmp(files->name, name))
  969. X           break;
  970. X      *last = files;
  971. X      files = files->next;
  972. X     }
  973. X     if (files) {
  974. X      files->specified = (files->specified || specified);
  975. X      *last = files;
  976. X      return 0;
  977. X     }
  978. X     if (*last) {
  979. X      (*last)->next = (filerec *) Malloc((unsigned) sizeof(filerec));
  980. X      if (! (*last)->next) {
  981. X           set_error(errno);
  982. X           error("Malloc");
  983. X           return error_code;
  984. X      }
  985. X      *(*last)->next = default_file;
  986. X      (*last)->next->previous = *last;
  987. X      (*last)->next->parent = parent;
  988. X      (*last) = (*last)->next;
  989. X     }
  990. X     else {
  991. X      parent->files = (filerec *) Malloc(sizeof(filerec));
  992. X      if (! parent->files) {
  993. X           set_error(errno);
  994. X           error("Malloc");
  995. X           return error_code;
  996. X      }
  997. X      *parent->files = default_file;
  998. X      parent->files->parent = parent;
  999. X      parent->files->previous = (filerec *) NULL;
  1000. X      *last = parent->files;
  1001. X     }
  1002. X     (void) strcpy((*last)->name, name);
  1003. X     (*last)->specified = specified;
  1004. X     return 0;
  1005. X}
  1006. X
  1007. X
  1008. X
  1009. X
  1010. X
  1011. Xint add_directory_to_parent(parent, name, specified, last)
  1012. Xfilerec *parent, **last;
  1013. Xchar *name;
  1014. XBoolean specified;
  1015. X{
  1016. X     filerec *directories;
  1017. X
  1018. X     *last = (filerec *) NULL;
  1019. X     directories = parent->dirs;
  1020. X     while (directories) {
  1021. X      if (! strcmp(directories->name, name))
  1022. X           break;
  1023. X      (*last) = directories;
  1024. X      directories = directories->next;
  1025. X     }
  1026. X     if (directories) {
  1027. X      directories->specified = (directories->specified || specified);
  1028. X      *last = directories;
  1029. X      return 0;
  1030. X     }
  1031. X     if (*last) {
  1032. X      (*last)->next = (filerec *) Malloc(sizeof(filerec));
  1033. X      if (! (*last)->next) {
  1034. X           set_error(errno);
  1035. X           error("Malloc");
  1036. X           return error_code;
  1037. X      }
  1038. X      *(*last)->next = default_directory;
  1039. X      (*last)->next->previous = *last;
  1040. X      (*last)->next->parent = parent;
  1041. X      (*last) = (*last)->next;
  1042. X     }
  1043. X     else {
  1044. X      parent->dirs = (filerec *) Malloc(sizeof(filerec));
  1045. X      if (! parent->dirs) {
  1046. X           set_error(errno);
  1047. X           error("Malloc");
  1048. X           return error_code;
  1049. X      }
  1050. X      *parent->dirs = default_directory;
  1051. X      parent->dirs->parent = parent;
  1052. X      parent->dirs->previous = (filerec *) NULL;
  1053. X      (*last) = parent->dirs;
  1054. X     }
  1055. X     (void) strcpy((*last)->name, name);
  1056. X     (*last)->specified = specified;
  1057. X     return 0;
  1058. X}
  1059. X
  1060. X
  1061. X
  1062. X
  1063. X
  1064. Xvoid free_leaf(leaf)
  1065. Xfilerec *leaf;
  1066. X{
  1067. X     leaf->freed = True;
  1068. X     if (! (leaf->dirs || leaf->files)) {
  1069. X      if (leaf->previous)
  1070. X           leaf->previous->next = leaf->next;
  1071. X      if (leaf->next)
  1072. X           leaf->next->previous = leaf->previous;
  1073. X      if (leaf->parent) {
  1074. X           if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
  1075. X            if (leaf->parent->dirs == leaf) {
  1076. X             leaf->parent->dirs = leaf->next;
  1077. X             if (leaf->parent->freed)
  1078. X                  free_leaf(leaf->parent);
  1079. X            }
  1080. X           }
  1081. X           else {
  1082. X            if (leaf->parent->files == leaf) {
  1083. X             leaf->parent->files = leaf->next;
  1084. X             if (leaf->parent->freed)
  1085. X                  free_leaf(leaf->parent);
  1086. X            }
  1087. X           }
  1088. X           free((char *) leaf);
  1089. X      }
  1090. X     }
  1091. X}     
  1092. X
  1093. X
  1094. X
  1095. Xint find_child(directory, name, child)
  1096. Xfilerec *directory, **child;
  1097. Xchar *name;
  1098. X{
  1099. X     filerec *ptr;
  1100. X     
  1101. X     *child = (filerec *) NULL;
  1102. X     if ((directory->specs.st_mode & S_IFMT) != S_IFDIR)
  1103. X      return DIR_NOT_DIRECTORY;
  1104. X     ptr = directory->dirs;
  1105. X     while (ptr)
  1106. X      if (strcmp(ptr->name, name))
  1107. X           ptr = ptr->next;
  1108. X      else
  1109. X           break;
  1110. X     if (ptr) {
  1111. X      *child = ptr;
  1112. X      return DIR_MATCH;
  1113. X     }
  1114. X     ptr = directory->files;
  1115. X     while (ptr)
  1116. X      if (strcmp(ptr->name, name))
  1117. X           ptr = ptr->next;
  1118. X          else
  1119. X           break;
  1120. X     if (ptr) {
  1121. X      *child = ptr;
  1122. X      return DIR_MATCH;
  1123. X     }
  1124. X     set_status(DIR_NO_MATCH);
  1125. X     return DIR_NO_MATCH;
  1126. X}
  1127. X
  1128. X
  1129. X
  1130. X
  1131. X
  1132. Xint change_path(old_path, new_path)
  1133. Xchar *old_path, *new_path;
  1134. X{
  1135. X     char next_old[MAXNAMLEN], next_new[MAXNAMLEN];
  1136. X     char rest_old[MAXPATHLEN], rest_new[MAXPATHLEN];
  1137. X     int retval;
  1138. X     filerec *current;
  1139. X     
  1140. X     if (*old_path == '/') {
  1141. X      current = &root_tree;
  1142. X      old_path++;
  1143. X      new_path++;
  1144. X     }
  1145. X     else if (! strncmp(old_path, "./", 2)) {
  1146. X      current = &cwd_tree;
  1147. X      old_path += 2;
  1148. X      new_path += 2;
  1149. X     }
  1150. X     else
  1151. X      current = &cwd_tree;
  1152. X     
  1153. X     (void) strcpy(next_old, firstpart(old_path, rest_old));
  1154. X     (void) strcpy(next_new, firstpart(new_path, rest_new));
  1155. X     while (*next_old && *next_new) {
  1156. X      retval = find_child(current, next_old, ¤t);
  1157. X      if (retval == DIR_MATCH) {
  1158. X           if (current) {
  1159. X            (void) strcpy(current->name, next_new);
  1160. X            current->specified = False;
  1161. X           }
  1162. X           else {
  1163. X            set_error(INTERNAL_ERROR);
  1164. X            error("change_path");
  1165. X            return error_code;
  1166. X           }
  1167. X      }
  1168. X      else {
  1169. X           error("change_path");
  1170. X           return retval;
  1171. X      }
  1172. X      
  1173. X      (void) strcpy(next_old, firstpart(rest_old, rest_old));
  1174. X      (void) strcpy(next_new, firstpart(rest_new, rest_new));
  1175. X     }
  1176. X     return 0;
  1177. X}
  1178. X
  1179. X
  1180. Xint get_leaf_path(leaf, leaf_buf)
  1181. Xfilerec *leaf;
  1182. Xchar leaf_buf[]; /* RETURN */
  1183. X{
  1184. X     char *name_ptr;
  1185. X
  1186. X     name_ptr = Malloc(1);
  1187. X     if (! name_ptr) {
  1188. X      set_error(errno);
  1189. X      error("Malloc");
  1190. X      *leaf_buf = '\0';
  1191. X      return error_code;
  1192. X     }
  1193. X     *name_ptr = '\0';
  1194. X     do {
  1195. X      name_ptr = realloc((char *) name_ptr, (unsigned)
  1196. X                 (strlen(leaf->name) + strlen(name_ptr) + 2));
  1197. X      if (! name_ptr) {
  1198. X           set_error(errno);
  1199. X           *leaf_buf = '\0';
  1200. X           error("realloc");
  1201. X           return error_code;
  1202. X      }
  1203. X      (void) strcpy(leaf_buf, name_ptr);
  1204. X      *name_ptr = '\0';
  1205. X      if (leaf->parent) if (leaf->parent->parent)
  1206. X           (void) strcat(name_ptr, "/");
  1207. X      (void) strcat(name_ptr, leaf->name);
  1208. X      (void) strcat(name_ptr, leaf_buf);
  1209. X      leaf = leaf->parent;
  1210. X     } while (leaf);
  1211. X     (void) strcpy(leaf_buf, name_ptr);
  1212. X     return 0;
  1213. X}
  1214. X
  1215. X
  1216. X
  1217. X
  1218. X
  1219. Xint accumulate_names(leaf, in_strings, num)
  1220. Xfilerec *leaf;
  1221. Xchar ***in_strings;
  1222. Xint *num;
  1223. X{
  1224. X     char newname[MAXPATHLEN];
  1225. X     char **strings;
  1226. X     int retval;
  1227. X     
  1228. X     strings = *in_strings;
  1229. X     if (leaf->specified) {
  1230. X      *num += 1;
  1231. X      strings = (char **) realloc((char *) strings, (unsigned)
  1232. X                      (sizeof(char *) * (*num)));
  1233. X      if (! strings) {
  1234. X           set_error(errno);
  1235. X           error("realloc");
  1236. X           return error_code;
  1237. X      }
  1238. X      if (retval = get_leaf_path(leaf, newname)) {
  1239. X           error("get_leaf_path");
  1240. X           return retval;
  1241. X      }
  1242. X      (void) convert_to_user_name(newname, newname);
  1243. X      strings[*num - 1] = Malloc((unsigned) (strlen(newname) + 1));
  1244. X      if (! strings[*num - 1]) {
  1245. X           set_error(errno);
  1246. X           error("Malloc");
  1247. X           return error_code;
  1248. X      }
  1249. X      (void) strcpy(strings[*num - 1], newname);
  1250. X     }
  1251. X     if (leaf->files) if (retval = accumulate_names(leaf->files, &strings,
  1252. X                            num)) {
  1253. X      error("accumulate_names");
  1254. X      return retval;
  1255. X     }
  1256. X     if (leaf->dirs) if (retval = accumulate_names(leaf->dirs, &strings,
  1257. X                           num)) {
  1258. X      error("accumulate_names");
  1259. X      return retval;
  1260. X     }
  1261. X     if (leaf->next) if (retval = accumulate_names(leaf->next, &strings,
  1262. X                           num)) {
  1263. X      error("accumulate_names");
  1264. X      return retval;
  1265. X     }
  1266. X
  1267. X     *in_strings = strings;
  1268. X     return 0;
  1269. X}
  1270. END_OF_FILE
  1271. if test 14682 -ne `wc -c <'directories.c'`; then
  1272.     echo shar: \"'directories.c'\" unpacked with wrong size!
  1273. fi
  1274. # end of 'directories.c'
  1275. fi
  1276. if test -f 'pattern.c' -a "${1}" != "-c" ; then 
  1277.   echo shar: Will not clobber existing file \"'pattern.c'\"
  1278. else
  1279. echo shar: Extracting \"'pattern.c'\" \(23196 characters\)
  1280. sed "s/^X//" >'pattern.c' <<'END_OF_FILE'
  1281. X/*
  1282. X * $Source: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/pattern.c,v $
  1283. X * $Author: jik $
  1284. X *
  1285. X * This program is part of a package including delete, undelete,
  1286. X * lsdel, expunge and purge.  The software suite is meant as a
  1287. X * replacement for rm which allows for file recovery.
  1288. X * 
  1289. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  1290. X * For copying and distribution information, see the file "mit-copyright.h."
  1291. X */
  1292. X
  1293. X#if (!defined(lint) && !defined(SABER))
  1294. X     static char rcsid_pattern_c[] = "$Header: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/pattern.c,v 1.16 90/01/11 04:11:58 jik Exp $";
  1295. X#endif
  1296. X
  1297. X#include <stdio.h>
  1298. X#include <sys/types.h>
  1299. X#include <sys/dir.h>
  1300. X#include <sys/param.h>
  1301. X#include <strings.h>
  1302. X#include <sys/stat.h>
  1303. X#include <errno.h>
  1304. X#include <com_err.h>
  1305. X#include "directories.h"
  1306. X#include "pattern.h"
  1307. X#include "util.h"
  1308. X#include "undelete.h"
  1309. X#include "shell_regexp.h"
  1310. X#include "mit-copyright.h"
  1311. X#include "delete_errs.h"
  1312. X#include "errors.h"
  1313. X#include "stack.h"
  1314. X
  1315. Xextern char *realloc();
  1316. Xextern int errno;
  1317. Xextern char *whoami;
  1318. X
  1319. Xvoid free_list();
  1320. X
  1321. X
  1322. X/*
  1323. X * add_arrays() takes pointers to two arrays of char **'s and their
  1324. X * lengths, merges the two into the first by realloc'ing the first and
  1325. X * then free's the second's memory usage.
  1326. X */  
  1327. Xint add_arrays(array1, num1, array2, num2)
  1328. Xchar ***array1, ***array2;
  1329. Xint *num1, *num2;
  1330. X{
  1331. X     int counter;
  1332. X     
  1333. X     *array1 = (char **) realloc((char *) *array1, (unsigned)
  1334. X                 (sizeof(char *) * (*num1 + *num2)));
  1335. X     if (! *array1) {
  1336. X      set_error(errno);
  1337. X      error("realloc");
  1338. X      return error_code;
  1339. X     }
  1340. X     for (counter = *num1; counter < *num1 + *num2; counter++)
  1341. X      *(*array1 + counter) = *(*array2 + counter - *num1);
  1342. X     free ((char *) *array2);
  1343. X     *num1 += *num2;
  1344. X     return 0;
  1345. X}
  1346. X
  1347. X
  1348. X
  1349. X
  1350. X
  1351. X
  1352. X/*
  1353. X * Add a string to a list of strings.
  1354. X */
  1355. Xint add_str(strs, num, str)
  1356. Xchar ***strs;
  1357. Xint num;
  1358. Xchar *str;
  1359. X{
  1360. X     char **ary;
  1361. X
  1362. X     ary = *strs = (char **) realloc((char *) *strs, (unsigned)
  1363. X                     (sizeof(char *) * (num + 1)));
  1364. X     if (! *strs) {
  1365. X      set_error(errno);
  1366. X      error("realloc");
  1367. X      return error_code;
  1368. X     }
  1369. X     ary[num] = Malloc((unsigned) (strlen(str) + 1));
  1370. X     if (! ary[num]) {
  1371. X      set_error(errno);
  1372. X      error("Malloc");
  1373. X      return error_code;
  1374. X     }
  1375. X     (void) strcpy(ary[num], str);
  1376. X     return 0;
  1377. X}
  1378. X
  1379. X
  1380. X
  1381. X
  1382. X
  1383. X/*
  1384. X * Find_matches will behave unpredictably if you try to use it to find
  1385. X * very strange combinations of file types, for example only searching
  1386. X * for undeleted files in the top-level directory, while searching
  1387. X * recursively for deleted files.  Basically, there are some conflicts
  1388. X * between options that I don't list here because I don't think I'll
  1389. X * ever need to use those combinations.
  1390. X */
  1391. X/*
  1392. X * Function: find_matches(char *name, int *num_found, char ***found,
  1393. X *                 int options)
  1394. X *
  1395. X * Requires: name points to a NULL-terminated string, representing a
  1396. X *   filename pattern with regular filename characters, path
  1397. X *   separators and shell wildcard characters []*?; num_found points
  1398. X *   to a valid int memory storage location; found points to a valid
  1399. X *   char ** memory storage location.
  1400. X *
  1401. X * Effects: Returns a list of all the files in the file hierarchy that
  1402. X *   match the options specified in options and that match name.
  1403. X *   Options are:
  1404. X *
  1405. X *   FIND_UNDELETED search for and return undeleted files
  1406. X * 
  1407. X *   FIND_DELETED search for and return deleted files
  1408. X *
  1409. X *   FIND_CONTENTS means that if matches are directories (or links to
  1410. X *     directories), the contents of the directory should be matched
  1411. X *     in addition to the directory itself
  1412. X * 
  1413. X *   RECURS_FIND_DELETED to search all undeleted subdirectories
  1414. X *     recursively of matched directories looking for deleted files
  1415. X *
  1416. X *   RECURS_FIND_UNDELETED to search all undeleted subdirectories
  1417. X *     recursively of matched directories looking for undeleted files
  1418. X * 
  1419. X *   RECURS_DELETED to recursively return all contents of deleted
  1420. X *     directories in addition to the directories themselves
  1421. X *   
  1422. X *   FOLLW_LINKS to pursue symlinks to directories and continue down
  1423. X *     the referenced directories when searching recursively (if the
  1424. X *     initial string is an undeleted symlink it is always traversed;
  1425. X *     deleted symlinks are never traversed)
  1426. X *   
  1427. X *   FOLLW_MOUNTPOINTS to traverse mount points when searching
  1428. X *     recursively (if the initial string is a mountpoint it is always
  1429. X *     traversed)
  1430. X *
  1431. X *   FIND_DOTFILES forces the system to recognize dot files instead of
  1432. X *     discarding them when looking for files
  1433. X *
  1434. X *   If the first character of name is '/', the search is conducted
  1435. X *   absolutely from the root of the hierarchy; else, it is conducted
  1436. X *   relative to the current working directory.  The number of
  1437. X *   matching files is returned in *num_found, and a list of file
  1438. X *   names is returned in *found.  If there are no errors, the return
  1439. X *   value is 0; else the return value represents the error code of
  1440. X *   the error which occurred.  No matter how many file names are
  1441. X *   returned, the memory location addressed in *found is a valid
  1442. X *   pointer according to Malloc() and can be released using free()
  1443. X *   safely.  However, if an error value is returned, the caller
  1444. X *   should not attempt to use the values stored in *num_found or
  1445. X *   *found.
  1446. X *
  1447. X * Modifies: *num_found, *found.
  1448. X */
  1449. Xint find_matches(name, num_found, found, options)
  1450. Xchar *name;
  1451. Xint *num_found;
  1452. Xchar ***found;
  1453. Xint options;
  1454. X{
  1455. X     char     **matched_files, **return_files, **recurs_files;
  1456. X     int     num_matched_files = 0, num_return_files = 0,
  1457. X                num_recurs_files = 0;
  1458. X     int    retval;
  1459. X     int    i;
  1460. X#ifdef DEBUG
  1461. X     int    j;
  1462. X#endif
  1463. X     int    match_options = 0;
  1464. X
  1465. X#ifdef DEBUG
  1466. X     fprintf(stderr, "Entering find_matches, name = %s, options = %d.\n",
  1467. X         name, options);
  1468. X#endif
  1469. X     
  1470. X     match_options = options & (FIND_DELETED | FIND_UNDELETED);
  1471. X     if (options & (RECURS_FIND_DELETED | RECURS_FIND_UNDELETED |
  1472. X            FIND_CONTENTS))
  1473. X      match_options |= FIND_UNDELETED;
  1474. X     
  1475. X     if (! match_options) {
  1476. X      set_error(PAT_NO_FILES_REQUESTED);
  1477. X      error("find_matches");
  1478. X      return error_code;
  1479. X     }
  1480. X     
  1481. X     retval = do_match(name, &num_matched_files, &matched_files,
  1482. X               match_options & FIND_UNDELETED,
  1483. X               match_options & FIND_DELETED);
  1484. X     if (retval) {
  1485. X      error(name);
  1486. X      return retval;
  1487. X     }
  1488. X     if (num_matched_files == 0) {
  1489. X      *num_found = num_matched_files;
  1490. X      *found = matched_files;
  1491. X#ifdef DEBUG
  1492. X      fprintf(stderr, "No matches found, returning.\n");
  1493. X#endif
  1494. X      return 0;
  1495. X     }
  1496. X
  1497. X#ifdef DEBUG
  1498. X     fprintf(stderr, "The following matches were found:\n");
  1499. X     for (i = 0; i < num_matched_files; i++)
  1500. X      fprintf(stderr, "  %s\n", matched_files[i]);
  1501. X#endif
  1502. X     
  1503. X     if (options & RECURS) {
  1504. X      return_files = (char **) Malloc(0);
  1505. X      if (! return_files) {
  1506. X           set_error(errno);
  1507. X           error("Malloc");
  1508. X           return error_code;
  1509. X      }
  1510. X      num_return_files = 0;
  1511. X
  1512. X      for (i = 0; i < num_matched_files; i++) {
  1513. X
  1514. X           retval = do_recurs(matched_files[i], &num_recurs_files,
  1515. X                  &recurs_files, options);
  1516. X           if (retval) {
  1517. X            error(matched_files[i]);
  1518. X            return retval;
  1519. X           }
  1520. X
  1521. X           if (num_recurs_files) {
  1522. X            retval = add_arrays(&return_files, &num_return_files,
  1523. X                    &recurs_files, &num_recurs_files);
  1524. X            if (retval) {
  1525. X             error("add_arrays");
  1526. X             return retval;
  1527. X            }
  1528. X#ifdef DEBUG
  1529. X            fprintf(stderr,
  1530. X                "Just added the following to return_files:\n");
  1531. X            for (j = num_return_files - num_recurs_files;
  1532. X             j < num_return_files; j++)
  1533. X             fprintf(stderr, "  %s\n", return_files[j]);
  1534. X#endif
  1535. X           }
  1536. X           
  1537. X           if (is_deleted(lastpart(matched_files[i]))) {
  1538. X            if (options & FIND_DELETED) {
  1539. X             retval = add_str(&return_files, num_return_files,
  1540. X                      matched_files[i]);
  1541. X             if (retval) {
  1542. X                  error("add_str");
  1543. X                  return retval;
  1544. X             }
  1545. X             num_return_files++;
  1546. X#ifdef DEBUG
  1547. X             fprintf(stderr, "Just added %s to return_files.\n",
  1548. X                 return_files[num_return_files-1]);
  1549. X#endif
  1550. X            }
  1551. X           }
  1552. X           else if (options & FIND_UNDELETED) {
  1553. X            retval = add_str(&return_files, num_return_files,
  1554. X                     matched_files[i]);
  1555. X            if (retval) {
  1556. X             error("add_str");
  1557. X             return retval;
  1558. X            }
  1559. X            num_return_files++;
  1560. X#ifdef DEBUG
  1561. X            fprintf(stderr, "Just added %s to return_files.\n",
  1562. X                return_files[num_return_files-1]);
  1563. X#endif
  1564. X           }
  1565. X      }
  1566. X      free_list(matched_files, num_matched_files);
  1567. X      *num_found = num_return_files;
  1568. X      *found = return_files;
  1569. X     }
  1570. X     else {
  1571. X      *num_found = num_matched_files;
  1572. X      *found = matched_files;
  1573. X     }
  1574. X
  1575. X     return 0;
  1576. X}
  1577. X
  1578. X
  1579. X
  1580. X
  1581. X      
  1582. X      
  1583. X            
  1584. X           
  1585. X#define string_push(str)\
  1586. X      strsize = strlen(str);\
  1587. X      retval = push(str, strsize);\
  1588. X      if (! retval)\
  1589. X           retval |= push(&strsize, sizeof(int));\
  1590. X      if (retval) {\
  1591. X           error("push");\
  1592. X           (void) popall();\
  1593. X           return retval;\
  1594. X      }
  1595. X#define string_pop(str)\
  1596. X      retval = pop(&strsize, sizeof(int));\
  1597. X      if (! retval)\
  1598. X           retval = pop(str, strsize);\
  1599. X      if (! retval)\
  1600. X           str[strsize] = '\0'
  1601. X      
  1602. X      
  1603. X
  1604. X
  1605. X
  1606. X
  1607. X/*
  1608. X * Function: do_match(char *name, int *num_found, char ***found,
  1609. X *               Boolean match_undeleted, Boolean match_deleted)
  1610. X *
  1611. X * Requires: name points to a NULL-terminated string, representing a
  1612. X *   filename pattern with regular filename characters, path
  1613. X *   separators and shell wildcard characters []*?; num_found points
  1614. X *   to a valid int memory storage location; found points to a valid
  1615. X *   char ** memory storage location.
  1616. X *
  1617. X * Effects: Returns a list of all the files in the file hierarchy that
  1618. X *   match name.  If match_undeleted is true, will return undeleted
  1619. X *   files that match; if match_deleted is true, will return
  1620. X *   deleted_files that match.  If the first character of name is '/',
  1621. X *   the search is conducted absolutely from the root of the
  1622. X *   hierarchy; else, it is conducted relative to the current working
  1623. X *   directory.  The number of matching files is returned in
  1624. X *   *num_found, and a list of file names is returned in *found.  If
  1625. X *   there are no errors, the return value is 0; else the return value
  1626. X *   represents the error code of the error which occurred.  No matter
  1627. X *   how many file names are returned, the memory location addressed
  1628. X *   in *found is a valid pointer according to Malloc() and can be
  1629. X *   released using free() safely.  However, if an error value is
  1630. X *   returned, the caller should not attempt to use the values stored
  1631. X *   in *num_found or *found.
  1632. X *
  1633. X * Modifies: *num_found, *found.
  1634. X *
  1635. X * Algorithm:
  1636. X *
  1637. X * start:
  1638. X *   base = "" or "/",
  1639. X *   name = name or name + 1
  1640. X *   initialze found and num_found
  1641. X *   dirp = Opendir(base)
  1642. X *   first = firstpart(name, rest) (assigns rest as side-effect)
  1643. X *   if (! *first) {
  1644. X *     add string to list if appropriate
  1645. X *     return
  1646. X * 
  1647. X * loop:
  1648. X *   dp = readdir(dirp)
  1649. X *   if (! dp) goto updir
  1650. X *   compare dp->d_name to first -- match?
  1651. X *     yes - goto downdir
  1652. X *     no - are we looking for deleted and is dp->d_name deleted?
  1653. X *       yes - compare undeleted dp->d_name to first -- match?
  1654. X *         yes - goto downdir
  1655. X *         no - goto loop
  1656. X *       no - goto loop
  1657. X *
  1658. X * downdir:
  1659. X *   save dirp, rest, first and base on stack
  1660. X *   first = firstpart(rest, rest)
  1661. X *   base = dp->d_name appended to base
  1662. X *   is first an empty string?
  1663. X *      yes - put back dirp, rest, first, base
  1664. X *            goto loop
  1665. X *   try to open dir base - opens?
  1666. X *      yes - goto loop
  1667. X *      no - is the error ENOTDIR?
  1668. X *           yes - don't worry about it
  1669. X *            no - report the error
  1670. X *          restore dirp, rest, first, base from stack
  1671. X *           goto loop
  1672. X *
  1673. X * updir:
  1674. X *   close dirp
  1675. X *   restore base, rest, first from stack
  1676. X *   STACK_EMPTY?
  1677. X *     yes - return from procedure with results
  1678. X *   restore dirp from stack
  1679. X *   goto loop
  1680. X */
  1681. Xint do_match(name, num_found, found, match_undeleted, match_deleted)
  1682. Xchar *name;
  1683. Xint *num_found;
  1684. Xchar ***found;
  1685. XBoolean match_undeleted, match_deleted;
  1686. X{
  1687. X     char base[MAXPATHLEN];
  1688. X     struct direct *dp;
  1689. X     DIR *dirp;
  1690. X     char first[MAXNAMLEN], rest[MAXPATHLEN];
  1691. X     int retval;
  1692. X     int strsize;
  1693. X     
  1694. X#ifdef DEBUG
  1695. X     printf("do_match: looking for %s\n", name);
  1696. X#endif
  1697. X
  1698. X     /* start: */
  1699. X     
  1700. X     if (*name == '/') {
  1701. X      *base = '/';
  1702. X      *(base + 1) = '\0';
  1703. X      name++;
  1704. X     }
  1705. X     else 
  1706. X      *base = '\0';
  1707. X
  1708. X     *found = (char **) Malloc(0);
  1709. X     if (! *found) {
  1710. X      set_error(errno);
  1711. X      error("Malloc");
  1712. X      return error_code;
  1713. X     }
  1714. X     *num_found = 0;
  1715. X     
  1716. X     dirp = Opendir(base);
  1717. X     if (! dirp) {
  1718. X      set_error(errno);
  1719. X      error(base);
  1720. X      return error_code;
  1721. X     }
  1722. X     (void) strcpy(first, firstpart(name, rest));
  1723. X     if ((! *first) && (match_undeleted)) {
  1724. X      retval = add_str(found, *num_found, base);
  1725. X      if (retval) {
  1726. X           error("add_str");
  1727. X           (void) popall();
  1728. X           return retval;
  1729. X      }
  1730. X      (*num_found)++;
  1731. X      return 0;
  1732. X     }
  1733. X     
  1734. X     while (1) {
  1735. X      dp = readdir(dirp);
  1736. X      if (! dp) goto updir;
  1737. X
  1738. X      retval = reg_cmp(first, dp->d_name);
  1739. X      if (retval < 0) {
  1740. X           error("reg_cmp");
  1741. X           goto updir;
  1742. X      }
  1743. X
  1744. X      if (retval == REGEXP_MATCH) goto downdir;
  1745. X
  1746. X      if (is_deleted(dp->d_name) && match_deleted) {
  1747. X           retval = reg_cmp(first, &dp->d_name[2]);
  1748. X           if (retval < 0) {
  1749. X            error("reg_cmp");
  1750. X            goto updir;
  1751. X           }
  1752. X
  1753. X           if (retval == REGEXP_MATCH)
  1754. X            goto downdir;
  1755. X           else
  1756. X            continue;
  1757. X      }
  1758. X      else
  1759. X           continue;
  1760. X
  1761. X     downdir:
  1762. X      retval = push(&dirp, sizeof(DIR *));
  1763. X      if (retval) {
  1764. X           error("push");
  1765. X           (void) popall();
  1766. X           return retval;
  1767. X      }
  1768. X      string_push(first);
  1769. X      string_push(rest);
  1770. X      string_push(base);
  1771. X      (void) strcpy(base, append(base, dp->d_name));
  1772. X      (void) strcpy(first, firstpart(rest, rest));
  1773. X      if (! *first) {
  1774. X           if (is_deleted(lastpart(base))) {
  1775. X            if (match_deleted) {
  1776. X             retval = add_str(found, *num_found, base);
  1777. X             if (retval) {
  1778. X                  error("add_str");
  1779. X                  (void) popall();
  1780. X                  return retval;
  1781. X             }
  1782. X             (*num_found)++;
  1783. X            }
  1784. X           }
  1785. X           else if (match_undeleted) {
  1786. X            retval = add_str(found, *num_found, base);
  1787. X            if (retval) {
  1788. X             error("add_str");
  1789. X             (void) popall();
  1790. X             return retval;
  1791. X            }
  1792. X            (*num_found)++;
  1793. X           }
  1794. X           string_pop(base);
  1795. X           string_pop(rest);
  1796. X           string_pop(first);
  1797. X           (void) pop(&dirp, sizeof(DIR *));
  1798. X           continue;
  1799. X      }
  1800. X      
  1801. X      dirp = Opendir(base);
  1802. X      if (! dirp) {
  1803. X           if (errno != ENOTDIR) {
  1804. X            set_error(errno);
  1805. X            error(base);
  1806. X           }
  1807. X           string_pop(base);
  1808. X           string_pop(rest);
  1809. X           string_pop(first);
  1810. X           (void) pop(&dirp, sizeof(DIR *));
  1811. X           continue;
  1812. X      }
  1813. X      else 
  1814. X           continue;
  1815. X
  1816. X     updir:
  1817. X      closedir(dirp);
  1818. X      string_pop(base);
  1819. X      if (retval) {
  1820. X           if (retval != STACK_EMPTY) {
  1821. X            error("pop");
  1822. X            (void) popall();
  1823. X            return retval;
  1824. X           }
  1825. X           return 0;
  1826. X      }
  1827. X      string_pop(rest);
  1828. X      string_pop(first);
  1829. X      retval = pop(&dirp, sizeof(DIR *));
  1830. X      if (retval) {
  1831. X           error("pop");
  1832. X           (void) popall();
  1833. X           return retval;
  1834. X      }
  1835. X      continue;
  1836. X     }
  1837. X}
  1838. X
  1839. X
  1840. X
  1841. X
  1842. X
  1843. X
  1844. X/*
  1845. X * Function: do_recurs(char *name, int *num_found, char ***found,
  1846. X *                int options)
  1847. X *
  1848. X * Requires: name points to a NULL-terminated string, representing a
  1849. X *   filename pattern with regular filename characters, path
  1850. X *   separators and shell wildcard characters []*?; num_found points
  1851. X *   to a valid int memory storage location; found points to a valid
  1852. X *   char ** memory storage location.
  1853. X *
  1854. X * Effects: Returns a list of all the files in the file hierarchy that
  1855. X *   are underneath the specified file, governed by the options set in
  1856. X *   options.  Options are as described in the find_matches() description.
  1857. X *   RECURS_FIND_DELETED and RECURS_DELETED imply FIND_DELETED.
  1858. X *   RECURS_FIND_UNDELETED implies FIND_UNDELETED.
  1859. X *
  1860. X * Modifies: *num_found, *found.
  1861. X *
  1862. X * Algorithm:
  1863. X *
  1864. X * start:
  1865. X *   initialze found and num_found
  1866. X *   strcopy(base, name)
  1867. X *   dirp = Opendir(base)
  1868. X *   check if we just opened a deleted symlink and return if we did
  1869. X *   check RECURS options and set FIND options as appropriate
  1870. X * 
  1871. X * loop:
  1872. X *   dp = readdir(dirp)
  1873. X *   if (! dp) goto updir
  1874. X *   is dp deleted?
  1875. X *     yes - is FIND_DELETED set?
  1876. X *             yes - add to list
  1877. X *                   is RECURS_DELETED set?
  1878. X *                   yes - goto downdir
  1879. X *                     no - goto loop
  1880. X *            no - goto loop
  1881. X *     no - is FIND_UNDELETED set?
  1882. X *            yes - is the file a dotfile?
  1883. X *               yes - is FIND_DOTFILES set?
  1884. X *                   yes - add to list
  1885. X *                 goto loop
  1886. X *               no - add to list
  1887. X *                  are RECURS_FIND_DELETED and FIND_DELETED set?
  1888. X *               yes - goto downdir
  1889. X *                  is RECURS_FIND_UNDELETED set?
  1890. X *               yes - goto downdir
  1891. X *               no - goto loop
  1892. X *           no - goto loop
  1893. X *             
  1894. X * downdir:
  1895. X *   save dirp, base on stack
  1896. X *   base = dp->d_name appended to base
  1897. X *   try to open base -- opens?
  1898. X *     yes - is FOLLW_LINKS set?
  1899. X *             yes - is it deleted?
  1900. X *              yes - is it a link?
  1901. X *                yes - close the directory
  1902. X *                  restore base and dirp
  1903. X *                  goto loop
  1904. X *             no - is it a link?
  1905. X *                     yes - close the directory
  1906. X *                  restore base and dirp
  1907. X *                  goto loop
  1908. X *           is FOLLW_MOUNTPOINTS set?
  1909. X *             no - is it a mountpoint?
  1910. X *                  yes - close the directory
  1911. X *                           restore base and dirp
  1912. X *                           goto loop
  1913. X *     no - is the error ENOTDIR?
  1914. X *           yes - don't worry about it
  1915. X *           no - report the error
  1916. X *         restore base and dirp
  1917. X *          goto loop
  1918. X * 
  1919. X * updir:
  1920. X *   close dirp
  1921. X *   restore base from stack
  1922. X *   STACK_EMPTY?
  1923. X *     yes - return from procedure with results
  1924. X *   restore dirp from stack
  1925. X *   goto loop
  1926. X */
  1927. Xint do_recurs(name, num_found, found, options)
  1928. Xchar *name;
  1929. Xint *num_found;
  1930. Xchar ***found;
  1931. Xint options;
  1932. X{
  1933. X     char base[MAXPATHLEN];
  1934. X     struct direct *dp;
  1935. X     DIR *dirp;
  1936. X     int retval;
  1937. X     int strsize;
  1938. X     struct stat statbuf;
  1939. X     int use_stat;
  1940. X     
  1941. X#ifdef DEBUG
  1942. X     fprintf(stderr, "do_recurs: opening %s\n", name);
  1943. X#endif
  1944. X
  1945. X     /* start: */
  1946. X     
  1947. X     *found = (char **) Malloc(0);
  1948. X     if (! *found) {
  1949. X      set_error(errno);
  1950. X      error("Malloc");
  1951. X      return error_code;
  1952. X     }
  1953. X     *num_found = 0;
  1954. X     strcpy(base, name);
  1955. X     
  1956. X     /* Never follow deleted symlinks */
  1957. X     if (is_deleted(lastpart(base)) && is_link(base, (struct stat *) NULL)) {
  1958. X      return 0;
  1959. X     }
  1960. X     
  1961. X     dirp = Opendir(base);
  1962. X     if (! dirp) {
  1963. X      /* If the problem is that it isn't a directory, just return */
  1964. X      /* with zero matches -- the file exists, but cannot be      */
  1965. X      /* recursively searched.  Otherwise, actually signal an     */
  1966. X      /* error.                               */
  1967. X      if (errno != ENOTDIR) {
  1968. X#ifdef DEBUG
  1969. X           fprintf(stderr, "Couldn't open %s.\n", base);
  1970. X#endif
  1971. X           set_error(errno);
  1972. X           error(base);
  1973. X           return error_code;
  1974. X      }
  1975. X      else
  1976. X           return 0;
  1977. X     }
  1978. X
  1979. X     if (options & (RECURS_FIND_DELETED | RECURS_DELETED))
  1980. X      options |= FIND_DELETED;
  1981. X     if (options & RECURS_FIND_UNDELETED)
  1982. X      options |= FIND_UNDELETED;
  1983. X     
  1984. X     while (1) {
  1985. X      dp = readdir(dirp);
  1986. X      if (! dp) goto updir;
  1987. X
  1988. X      if (is_deleted(dp->d_name)) {
  1989. X           if (options & FIND_DELETED) {
  1990. X            retval = add_str(found, *num_found,
  1991. X                     append(base, dp->d_name));
  1992. X            if (retval) {
  1993. X             error("add_str");
  1994. X             (void) popall();
  1995. X             return retval;
  1996. X            }
  1997. X            (*num_found)++;
  1998. X            if (options & RECURS_DELETED)
  1999. X             goto downdir;
  2000. X            else
  2001. X             continue;
  2002. X           }
  2003. X           else
  2004. X            continue;
  2005. X      }
  2006. X
  2007. X      if (options & FIND_UNDELETED) {
  2008. X           if (is_dotfile(dp->d_name)) {
  2009. X            if (options & FIND_DOTFILES) {
  2010. X             retval = add_str(found, *num_found,
  2011. X                      append(base, dp->d_name));
  2012. X             if (retval) {
  2013. X                  error("add_str");
  2014. X                  (void) popall();
  2015. X                  return retval;
  2016. X             }
  2017. X            }
  2018. X            continue;
  2019. X           }
  2020. X           else {
  2021. X            retval = add_str(found, *num_found,
  2022. X                     append(base, dp->d_name));
  2023. X            if (retval) {
  2024. X             error("add_str");
  2025. X             (void) popall();
  2026. X             return retval;
  2027. X            }
  2028. X            (*num_found)++;
  2029. X           }
  2030. X      }
  2031. X
  2032. X      if (! is_dotfile(dp->d_name)) {
  2033. X           if (options & RECURS_FIND_DELETED)
  2034. X            goto downdir;
  2035. X           if (options & RECURS_FIND_UNDELETED)
  2036. X            goto downdir;
  2037. X      }
  2038. X      
  2039. X      continue;
  2040. X      
  2041. X           
  2042. X     downdir:
  2043. X      retval = push(&dirp, sizeof(DIR *));
  2044. X      if (retval) {
  2045. X           error("push");
  2046. X           (void) popall();
  2047. X           return retval;
  2048. X      }
  2049. X      string_push(base);
  2050. X      (void) strcpy(base, append(base, dp->d_name));
  2051. X
  2052. X      /*
  2053. X       * Originally, I did an Opendir() right at the start and
  2054. X       * then only checked things if the Opendir resulted in an
  2055. X       * error.  However, this is inefficient, because the
  2056. X       * Opendir() procedure works by first calling open() on the
  2057. X       * file, and *then* calling fstat on the file descriptor
  2058. X       * that is returned.  since most of the time we will be
  2059. X       * trying to open things that are not directory, it is much
  2060. X       * more effecient to do the stat first here and to do the
  2061. X       * Opendir only if the stat results are satisfactory.
  2062. X       */
  2063. X      use_stat = (options & FOLLW_LINKS) && (! is_deleted(lastpart(base)));
  2064. X      if (use_stat)
  2065. X           retval = stat(base, &statbuf);
  2066. X      else
  2067. X           retval = lstat(base, &statbuf);
  2068. X      if (retval == -1) {
  2069. X           set_error(errno);
  2070. X           error(base);
  2071. X           string_pop(base);
  2072. X           (void) pop(&dirp, sizeof(DIR *));
  2073. X           continue;
  2074. X      }
  2075. X      /* It's not a directory, so punt it and continue. */
  2076. X      if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
  2077. X           string_pop(base);
  2078. X           (void) pop(&dirp, sizeof(DIR *));
  2079. X           continue;
  2080. X      }
  2081. X
  2082. X      /* Actually try to open it. */
  2083. X      dirp = Opendir(base);
  2084. X      if (! dirp) {
  2085. X           set_error(errno);
  2086. X           error(base);
  2087. X           string_pop(base);
  2088. X           (void) pop(&dirp, sizeof(DIR *));
  2089. X           continue;
  2090. X      }
  2091. X      
  2092. X      if (! (options & FOLLW_MOUNTPOINTS)) {
  2093. X           if (is_mountpoint(base, use_stat ? (struct stat *) NULL :
  2094. X                 &statbuf)) {
  2095. X            closedir(dirp);
  2096. X            set_warning(PAT_IS_MOUNT);
  2097. X            error(base);
  2098. X            string_pop(base);
  2099. X            (void) pop(&dirp, sizeof(DIR *));
  2100. X            continue;
  2101. X           }
  2102. X#ifdef DEBUG
  2103. X           else {
  2104. X            fprintf(stderr,
  2105. X                "do_recurs: %s isn't a mountpoint, following.\n",
  2106. X                base);
  2107. X           }
  2108. X#endif
  2109. X      }
  2110. X#ifdef DEBUG
  2111. X      printf("do_recurs: opening %s\n", base);
  2112. X#endif
  2113. X      continue;
  2114. X      
  2115. X     updir:
  2116. X      closedir(dirp);
  2117. X      string_pop(base);
  2118. X      if (retval) {
  2119. X           if (retval != STACK_EMPTY) {
  2120. X            error("pop");
  2121. X            (void) popall();
  2122. X            return retval;
  2123. X           }
  2124. X           return 0;
  2125. X      }
  2126. X      retval = pop(&dirp, sizeof(DIR *));
  2127. X      if (retval) {
  2128. X           error("pop");
  2129. X           (void) popall();
  2130. X           return retval;
  2131. X      }
  2132. X      continue;
  2133. X     }
  2134. X}
  2135. X
  2136. X
  2137. Xvoid free_list(list, num)
  2138. Xchar **list;
  2139. Xint num;
  2140. X{
  2141. X     int i;
  2142. X
  2143. X     for (i = 0; i < num; i++)
  2144. X      free(list[i]);
  2145. X
  2146. X     free((char *) list);
  2147. X}
  2148. X
  2149. X
  2150. X
  2151. X
  2152. X
  2153. X
  2154. X/*
  2155. X * returns true if the filename has no globbing wildcards in it.  That
  2156. X * means no non-quoted question marks, asterisks, or open square
  2157. X * braces.  Assumes a null-terminated string, and a valid globbing
  2158. X */
  2159. Xint no_wildcards(name)
  2160. Xchar *name;
  2161. X{
  2162. X     do {
  2163. X      switch (*name) {
  2164. X      case '\\':
  2165. X           name++;
  2166. X           break;
  2167. X      case '?':
  2168. X           return(0);
  2169. X      case '*':
  2170. X           return(0);
  2171. X      case '[':
  2172. X           return(0);
  2173. X      }
  2174. X     } while (*++name);
  2175. X     return(1);
  2176. X}
  2177. END_OF_FILE
  2178. if test 23196 -ne `wc -c <'pattern.c'`; then
  2179.     echo shar: \"'pattern.c'\" unpacked with wrong size!
  2180. fi
  2181. # end of 'pattern.c'
  2182. fi
  2183. echo shar: End of archive 3 \(of 3\).
  2184. cp /dev/null ark3isdone
  2185. MISSING=""
  2186. for I in 1 2 3 ; do
  2187.     if test ! -f ark${I}isdone ; then
  2188.     MISSING="${MISSING} ${I}"
  2189.     fi
  2190. done
  2191. if test "${MISSING}" = "" ; then
  2192.     echo You have unpacked all 3 archives.
  2193.     rm -f ark[1-9]isdone
  2194. else
  2195.     echo You still need to unpack the following archives:
  2196.     echo "        " ${MISSING}
  2197. fi
  2198. ##  End of shell archive.
  2199. exit 0
  2200. exit 0 # Just in case...
  2201.